import { CSSProperties } from "react";
import { create as defineStore } from "zustand"
import { immer } from "zustand/middleware/immer";
import { persist } from "zustand/middleware"

export interface Component {
    id: string;
    name: string;
    props: Record<string, any>;
    desc: string;
    styles?: CSSProperties
    children?: Component[]
    parentId?: string
}

interface State {
    components: Component[];
    mode: "edit" | "preview"
    curComponentId: string | null;
    curComponent: Component | null;
}

interface Action {
    addComponent: (component: Component, parentId?: string) => void;
    deleteComponent: (id: string) => void;
    updateComponentProps: (id: string, props: Record<string, any>) => void;
    updateComponentStyles: (id: string, styles: CSSProperties, replace?: boolean) => void;
    setCurComponentId: (id: string | null) => void;
    setMode: (mode: State["mode"]) => void
}


export const useComponentStore = defineStore<State & Action>()(logMiddleware(persist(immer((set, get) => ({
    components: [
        {
            id: "1",
            name: "Page",
            desc: "页面",
            props: {},
            children: [],
        }
    ],
    mode: "edit",
    curComponentId: null,
    curComponent: null,
    // 添加组件：如果存在父组件，则添加到父组件的children中，否则添加到根组件最后
    addComponent: (component: Component, parentId: string) => set((draft: State & Action) => {
        if (parentId) {
            const parantComponent = getComponentById(parentId, draft.components)
            if (parantComponent) {
                component = { ...component, parentId: parentId }
                parantComponent.children = parantComponent.children || []
                parantComponent.children.push(component)
            }
        } else {
            draft.components.push(component)
        }
    }),

    // 删除组件: 首先判断组件是否为根组件，如果是根组件，则直接删除，否则从父组件的children中删除的该组件
    deleteComponent: (id: string) => set((draft: State & Action) => {
        if(!id) return;
        const component = getComponentById(id, draft.components);
        if (component?.parentId) {
            // 非根组件
            const parentComponent = getComponentById(component.parentId, draft.components)
            if (parentComponent) {
                parentComponent.children = parentComponent?.children?.filter((item) => item.id !== id)
            }
        } else {
            // 根组件
            draft.components = draft.components.filter((item) => item.id !== id)
        }
    }),

    // 更新组件属性
    updateComponentProps: (id: string, props: Record<string, any>) => set((draft: State & Action) => {
        const component = getComponentById(id, draft.components)
        if (component) {
            component.props = { ...component.props, ...props };

            // 使用了 immer， set 里面的第一个参数不再是原始的 state，而是 draftState，两者不是同一份.因此需要更新 curComponent 的引用，确保指向最新的
            if (id === draft.curComponentId) {
                draft.curComponent = component;
            }
        }
    }),

    // 更新组件样式
    updateComponentStyles: (id: string, styles: CSSProperties, replace = false) => set((draft: State & Action) => {
        const component = getComponentById(id, draft.components)
        if (component) {
            component.styles = replace ? {...styles} : { ...component.styles, ...styles }

            // 使用了 immer， set 里面的第一个参数不再是原始的 state，而是 draftState，两者不是同一份.因此需要更新 curComponent 的引用，确保指向最新的
            if (id === draft.curComponentId) {
                draft.curComponent = component;
            }
        }
    }),

    // 记录 Click 时鼠标所在的组件
    setCurComponentId: (id: string) => set((draft: State & Action) => {
        draft.curComponentId = id
        draft.curComponent = getComponentById(id, draft.components)
    }),

    // 更改模式 
    setMode: (mode: State["mode"]) => set((draft: State & Action )=> {
        draft.mode = mode
    })
})),
{
    name: "todolist"
})))

// 根据 id 递归获取组件
export function getComponentById(id: string, components: Component[]): Component | null{
    if (!id) return null

    for (const component of components) {
        if (component.id === id) return component
        if (component.children && component.children.length > 0) {
            const result = getComponentById(id, component.children)
            if (result) return result
        }
    }
    return null
}


function logMiddleware(func){
    return function(set, get, store){
        const newSet = (value) => {
            console.log("set before", get().components)
            set(value)
            console.log("set after", get().components)
        }

        return func(newSet, get, store)
    }
}
 